# !/usr/bin/env python
# -*- coding:utf-8 -*-
"""
功能：学习装饰器
版本：2022-04-13 15:06 创建
"""
import inspect
import sys
import unittest
from datetime import datetime


class DecoratorTestCase(unittest.TestCase):
    def test_example1_without_decorator(self):
        """普通函数版本"""

        def time_cost(func):
            print(f'开始执行:{inspect.getframeinfo(inspect.currentframe().f_back)[2]}')
            start_time = datetime.now()
            result = func()
            print(f'{func} 耗时:{datetime.now() - start_time}')
            return result

        def fun1():
            print(f'执行:{sys._getframe().f_code.co_name}()')
            result = 0
            for i in range(100):
                result += i
            return result

        # 普通函数版本：统计函数 fun1() 耗时
        self.assertEqual(99 * 50, time_cost(fun1))

    def test_example1_with_decorator(self):
        """装饰器版本"""

        def time_cost(func):
            def warp():
                print(f'开始执行:{inspect.getframeinfo(inspect.currentframe().f_back)[2]}()')
                start_time = datetime.now()
                result = func()
                print(f'{func} 耗时:{datetime.now() - start_time}')
                return result

            return warp

        @time_cost
        def fun1():
            print(f'执行:{sys._getframe().f_code.co_name}()')
            result = 0
            for i in range(100):
                result += i
            return result

        # 装饰器版本：统计函数 fun1() 耗时
        self.assertEqual(99 * 50, fun1())

    def test_decorator_execution_order(self):
        """
        理解装饰器的定义与执行顺序
        当多个装饰器装饰一个函数时执行顺序：最先装饰的装饰器，最后一个执行。它遵循了先进后出规则 类似于stack
        """

        def log_fun(func):
            print('定义装饰器:log_fun')

            def inner_fun():
                print(f'开始执行:{func}')
                result = func()
                print(f'执行结果:{result}')
                return result

            return inner_fun

        def time_cost(func):
            print('定义装饰器:time_cost')

            def warp():
                print(f'统计{func}耗时')
                start_time = datetime.now()
                result = func()
                print(f'函数 {func.__name__}() 耗时:{datetime.now() - start_time}')
                return result

            return warp

        @log_fun
        @time_cost
        def fun1():
            print(f'执行:{sys._getframe().f_code.co_name}()')
            result = 0
            for i in range(100):
                result += i
            print(f'函数 {sys._getframe().f_code.co_name}() 执行结束')
            return result

        self.assertEqual(99 * 50, fun1())


if __name__ == '__main__':
    unittest.main()
